#include <jni.h>
#include <string>
#include <opencv2/opencv.hpp>

#include <android/log.h>
#include <android/native_window_jni.h>


using namespace cv;

DetectionBasedTracker *tracker = 0;

ANativeWindow *window = 0;

#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"David",__VA_ARGS__)

//Adapter
//实例化适配器
class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector {
public:
    //c++传参赋值，传入detector
    CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector): IDetector(), maniuDetector(detector) {}

    //重写detect方法
    void detect(const cv::Mat &image, std::vector<cv::Rect> &objects) {
//        代表最近邻
        maniuDetector->detectMultiScale(image, objects, scaleFactor, minNeighbours, 0, minObjSize,
                                   maxObjSize);
    }

private:
    CascadeDetectorAdapter();

    cv::Ptr<cv::CascadeClassifier> maniuDetector;
};


extern "C"
JNIEXPORT void JNICALL
Java_com_jyf_opencv_MainActivity_init(JNIEnv *env, jobject thiz, jstring model_path_) {

    const char *model = env->GetStringUTFChars(model_path_, 0);

    //创建一个检测器，功能就是CascadeClassifier *classifier=new CascadeClassifier(model);
    //Ptr是智能指针，当不需要的时候智能释放，通过opencv的Ptr来自动控制析构
    //opencv所有的对象都是交给智能指针来做的
    Ptr<CascadeClassifier> classifier = makePtr<CascadeClassifier>(model);
    //参照Recyclerview.Adapter
    Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(classifier);

    //创建一个跟踪器
    Ptr<CascadeClassifier> classifier1 = makePtr<CascadeClassifier>(model);
    Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(classifier1);

    DetectionBasedTracker::Parameters detectorParams;
    //参照Recyclerview
    tracker = new DetectionBasedTracker(mainDetector, trackingDetector, detectorParams);
    tracker->run();

    env->ReleaseStringUTFChars(model_path_, model);
}



extern "C"
JNIEXPORT void JNICALL
Java_com_jyf_opencv_MainActivity_postData(JNIEnv *env, jobject thiz, jbyteArray data_, jint w,
                                          jint h, jint cameraId) {


    // nv21的数据
    jbyte *data = env->GetByteArrayElements(data_, NULL);
    //Mat就是一个图像的意思
    Mat src(h + h / 2, w, CV_8UC1, data);
    //颜色格式的转换 nv21->RGBA
    //将 nv21的yuv数据转成了rgba
    cvtColor(src, src, COLOR_YUV2RGBA_NV21);
    // 正在写的过程 退出了，导致文件丢失数据

    //imwrite("/sdcard/src1.jpg",src);

    if (cameraId == 1) {
        //前置摄像头，需要逆时针旋转90度
        rotate(src, src, ROTATE_90_COUNTERCLOCKWISE);
        //水平翻转 镜像
        flip(src, src, 1);
    } else {
        //顺时针旋转90度
        rotate(src, src, ROTATE_90_CLOCKWISE);
    }
    Mat gray;
    //灰度图
    cvtColor(src, gray, COLOR_RGBA2GRAY);
    //imwrite("/sdcard/src2.jpg",src);
    //增强对比度 (直方图均衡)
    equalizeHist(gray, gray);
//    imwrite("/sdcard/src3.jpg",gray);




    //----------------------------------------------------------------
    LOGI("--------1");
    if (!tracker){
        LOGI("--------tracker maybe init error");
    }
    tracker->process(gray);
    LOGI("--------2");
    //取人脸集合list
    std::vector<Rect> faces;
    tracker->getObjects(faces);
    for (Rect face : faces) {

        //生成训练样本----------------------------------------start
        Mat m;
        m = gray(face).clone();
        resize(m, m, Size(24, 24));
//        imwrite("/sdcard/src4.jpg", m);
        //生成训练样本----------------------------------------end
        //画个矩形
        //src=旋转后的原图  画个蓝色的的矩形

        LOGI(" 识别出width: %d  height: %d",face.width, face.height);

        rectangle(src, face, Scalar(0, 0, 255));
    }


    if (window) {
        do {
            //给windows内存缓冲区设置大小
            ANativeWindow_setBuffersGeometry(window, src.cols, src.rows, WINDOW_FORMAT_RGBA_8888);
            ANativeWindow_Buffer buffer;
            int ret = ANativeWindow_lock(window, &buffer, 0);
            if (ret) {
                ANativeWindow_release(window);
                window = 0;
            }
//            rgba需要*4
            int srcLineSize=src.cols*4;

            int dstLineSize=buffer.stride*4;

            uint8_t *dstData = static_cast<uint8_t *>(buffer.bits);

            for (int i=0;i<buffer.height;i++){
                memcpy(dstData+i*dstLineSize,src.data+i*srcLineSize,srcLineSize);
            }
            ANativeWindow_unlockAndPost(window);

        } while (0);
    }






    env->ReleaseByteArrayElements(data_, data, 0);
}


extern "C"
JNIEXPORT void JNICALL
Java_com_jyf_opencv_MainActivity_setSurface(JNIEnv *env, jobject thiz, jobject surface) {
    if (window) {
        ANativeWindow_release(window);
        window = 0;
    }
    window = ANativeWindow_fromSurface(env, surface);


}